package com.cesc.demo.domain.product.service;

import com.cesc.demo.domain.product.IDomainService;
import com.cesc.demo.domain.product.PageResult;
import com.cesc.demo.domain.product.entity.Product;
import com.cesc.demo.domain.product.repository.ProductReactiveMysqlRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.r2dbc.core.R2dbcEntityTemplate;
import org.springframework.data.relational.core.query.Criteria;
import org.springframework.data.relational.core.query.Query;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.List;

import static org.springframework.data.relational.core.query.Criteria.where;

@Service
public class ProductDomainService implements IProductDomainService {

    private static  final Logger logger= LoggerFactory.getLogger(ProductDomainService.class);
    private static  final Logger backgroundLogger= LoggerFactory.getLogger("BackgroundLogger");

    @Autowired
    private  R2dbcEntityTemplate template;
    @Autowired
    private ProductReactiveMysqlRepository productReactiveMysqlRepository;

    /***
     * 通过底层API分页查询
     * @param product
     * @param pageSize
     * @param page
     * @return
     */
    @Override
    public Mono<PageResult<Product>> findByAccessApi(Product product, int pageSize, int page) {

        //计算每页获取记录数
        int pageOffset=0;
        pageOffset=(page-1)*pageSize;
        //排序条件
        Sort.Order order= Sort.Order.desc("id");
        Sort sort=Sort.by(order);

        String name=product.getProductName();
        String code=product.getProductCode();

        //生成查询条件
        Criteria criteria=Criteria.empty();
        if(name!=null&&name.length()>0) {
            Criteria criteriaName = where("productName").like("%" + name + "%");
            Criteria criteriaDescription=where("description").like("%" + name + "%");
            criteria=criteria.or(criteriaName).or(criteriaDescription);
        }
        if(code!=null&&code.length()>0) {
            Criteria criteriacode = where("productCode").like("%" + code + "%");
            criteria=criteria.and(criteriacode);
        }

        //计算总页数
        Mono<Long> totalRecordMono=  this.template.select(Product.class).matching(Query.query(criteria)).count();
        //获取结果
        Flux<Product> productFlux=this.template.select(Product.class)
                .matching(Query.query(criteria).limit(pageSize).offset(pageOffset).sort(sort))
                .all();

        Mono<List<Product>> productListMono=productFlux.collectList();

        //将两个流的结果合并
        return Mono.zip(totalRecordMono,productListMono).flatMapMany(data->{
            PageResult<Product> pageResult=new PageResult();
            pageResult.setTotalPage(data.getT1());
            pageResult.setRecords(data.getT2());
            return Mono.justOrEmpty(pageResult);
        }).last();

    }




    /***
     * 带事务通过reactor repository保存数据到数据，正常提交
     * @param product
     * @return
     */
    @Override
    public Mono<Product> saveByRespository(Product product) {
        return   this.productReactiveMysqlRepository.save(product);
    }

    /***
     * 带事务通过reactor repository保存数据到数据，发生异常回滚事务
     * @param product
     * @return
     */
    @Override
    public Mono<Product> saveByRespositoryWithRollBack(Product product) {

        return   this.productReactiveMysqlRepository.save(product).map(productdata ->{
            logger.info("保存商品:"+productdata.getId());
            logger.error("出错回滚，测试事务回滚");
            backgroundLogger.error("出错回滚，测试回滚事务日志");
            throw new IllegalStateException(); //触发事务回滚，一定要抛出IllegalStateException
        } );
    }


    /**
     * 根据商品id删除商品
     * @param id 商品ID
     * @return true 删除成功
     */
    @Override
    public Mono<Void> deletByIdByRespository(Long id) {


      Mono<Boolean> productMono=  this.productReactiveMysqlRepository.existsById(id);
      return productMono.flatMap(product ->{
          if(product==false)
             throw new IllegalStateException("商品不存在");
           return   this.productReactiveMysqlRepository.deleteById(id);
       });

    }


    /***
     * 通过respository查询数据
     * @param id
     * @return
     */
    @Override
    public Mono<Product> findByIdByRespository(Long id) {
        return this.productReactiveMysqlRepository.findById(id);
    }

    /***
     * 通过底层API新增数据
     * @param product
     * @return
     */
    @Override
    public Mono<Product> saveByAccessApi(Product product) {
        return this.template.insert(product);

    }


    /***
     * 通过底层API更新数据
     * @param product
     * @return
     */
    @Override
    public Mono<Product> updateByAccessApi(Product product) {
        return this.template.update(product);

    }

    /***
     * 通过底层API删除数据
     * @param product
     * @return
     */
    @Override
    public Mono<Integer> deleteByAccessApi(Product product) {
     return  this.template.delete(Product.class).matching(
              Query.query(
                      where("id").is(product.getId())
                              .or("productName").is(product.getProductName())
              )
      ).all();
    }


    @Override
    public Flux<Product> findProductByProductNameEquals(String productName) {
        return this.productReactiveMysqlRepository.findProductByProductNameEquals(productName);
    }
}
